package com.zhonglz.util.sm4;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import com.zhonglz.util.base64.Base64Utils;
import com.zhonglz.util.hex.HexUtils;
import com.zhonglz.util.md5.Md5Utils;

import cn.hutool.core.lang.UUID;


public class Sm4Utils {

	// 算法名称
	public static final String ALGORITHM_NAME = "SM4";

	// 密钥位数
	public static final int DEFAULT_KEY_SIZE = 128;

	// 按位数生成密钥
	public static byte[] generateKey() throws NoSuchAlgorithmException, NoSuchProviderException {
		KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
		kg.init(DEFAULT_KEY_SIZE, new SecureRandom());
		return kg.generateKey().getEncoded();
	}

	public static byte[] encryptEcbPadding(byte[] key, byte[] data)
			throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
			IllegalBlockSizeException, BadPaddingException {
		Cipher cipher = generateEcbCipher(Sm4CipherMode.SM4_ECB_PADDING, Cipher.ENCRYPT_MODE, key);
		return cipher.doFinal(data);
	}

	public static byte[] decryptEcbPadding(byte[] key, byte[] cipherText)
			throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException,
			NoSuchProviderException, NoSuchPaddingException {
		Cipher cipher = generateEcbCipher(Sm4CipherMode.SM4_ECB_PADDING, Cipher.DECRYPT_MODE, key);
		return cipher.doFinal(cipherText);
	}

	public static byte[] encryptEcbNoPadding(byte[] key, byte[] data)
			throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
			IllegalBlockSizeException, BadPaddingException {
		Cipher cipher = generateEcbCipher(Sm4CipherMode.SM4_ECB_NOPADDING, Cipher.ENCRYPT_MODE, key);
		return cipher.doFinal(data);
	}

	public static byte[] decryptEcbNoPadding(byte[] key, byte[] cipherText)
			throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException,
			NoSuchProviderException, NoSuchPaddingException {
		Cipher cipher = generateEcbCipher(Sm4CipherMode.SM4_ECB_NOPADDING, Cipher.DECRYPT_MODE, key);
		return cipher.doFinal(cipherText);
	}

	public static byte[] encryptCbcPadding(byte[] key, byte[] iv, byte[] data)
			throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
			IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
		Cipher cipher = generateCbcCipher(Sm4CipherMode.SM4_CBC_PADDING, Cipher.ENCRYPT_MODE, key, iv);
		return cipher.doFinal(data);
	}

	public static byte[] decryptCbcPadding(byte[] key, byte[] iv, byte[] cipherText)
			throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException,
			NoSuchProviderException, NoSuchPaddingException, InvalidAlgorithmParameterException {
		Cipher cipher = generateCbcCipher(Sm4CipherMode.SM4_CBC_PADDING, Cipher.DECRYPT_MODE, key, iv);
		return cipher.doFinal(cipherText);
	}

	public static byte[] encryptCbcNoPadding(byte[] key, byte[] iv, byte[] data)
			throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
			IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
		Cipher cipher = generateCbcCipher(Sm4CipherMode.SM4_CBC_NOPADDING, Cipher.ENCRYPT_MODE, key, iv);
		return cipher.doFinal(data);
	}

	public static byte[] decryptCbcNoPadding(byte[] key, byte[] iv, byte[] cipherText)
			throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException,
			NoSuchProviderException, NoSuchPaddingException, InvalidAlgorithmParameterException {
		Cipher cipher = generateCbcCipher(Sm4CipherMode.SM4_CBC_NOPADDING, Cipher.DECRYPT_MODE, key, iv);
		return cipher.doFinal(cipherText);
	}

	private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key)
			throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException {
		Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
		Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
		cipher.init(mode, sm4Key);
		return cipher;
	}

	private static Cipher generateCbcCipher(String algorithmName, int mode, byte[] key, byte[] iv)
			throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
			NoSuchProviderException, NoSuchPaddingException {
		Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
		Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
		IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
		cipher.init(mode, sm4Key, ivParameterSpec);
		return cipher;
	}
	
	
	public static void main(String[] args) throws Exception {
		Security.addProvider(new BouncyCastleProvider());
//		String str=HexUtils.encodeHex(Sm4Utils.generateKey());//生成数位KEY
//		System.out.println("key:"+str);
		
		///f2a8e7daff39894edf2e8da33950fd0c
		
		String str="f2a8e7daff39894edf2e8da33950fd0c";
		
		 String releaseId = UUID.randomUUID().toString(true);
		 System.out.println("id:"+releaseId);
	    
			
	     byte[] encryptEcbPadding = Sm4Utils.encryptEcbPadding(HexUtils.decodeHex(str), releaseId.getBytes("UTF8"));
	     String qiaminhou = Base64Utils.encode(encryptEcbPadding);
	     System.out.println("签名后的数据:"+qiaminhou);
	     
	     System.out.println("最终的链接:https://lowcode.easysign.cn/public/release/"+qiaminhou);
	     
		/*String str="342596c4c509e94a2f2b2d674a4cffd6";
		System.out.println("key:"+str);
		String phone="7629660804619374168";
		byte[] encryptEcbPadding = Sm4Utils.encryptEcbPadding(HexUtils.decodeHex(str), phone.getBytes("UTF8"));
		String result = Base64Utils.encode(encryptEcbPadding);
		System.out.println("加密："+result);
		byte[] or = Sm4Utils.decryptEcbPadding(HexUtils.decodeHex(str), Base64Utils.decode(result));
		System.out.println("解密："+new String(or,"UTF8"));*/
		
	}
	
}
